﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace ArkanoidX
{
    /// <summary>
    /// This is the main type for your _game
    /// </summary>
    public class MainGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager _graphics;
        SpriteBatch _spriteBatch = null;

        private Texture2D _backgroundTexture;    // texture as the background of the _game

        // sprites
        Racket _racket = null;
        Bricks _bricks = null;

        Ball _mainBall = null;

        public Racket Racket { get { return _racket; } }
        public Bricks Bricks { get { return _bricks; } }

        public MainGame()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the _game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per _game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            // load the sprite batch to the service collection
            Services.AddService(typeof(SpriteBatch), _spriteBatch);

            // TODO: use this.Content to load your _game content here
            _backgroundTexture = Content.Load<Texture2D>("bgimage");


        }

        /// <summary>
        /// UnloadContent will be called once per _game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the _game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the _game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here


            // Start if not started yet
            if (_racket == null)
            {
                Start();
            }

            KeyboardState keyboard = Keyboard.GetState();

            if ((keyboard.IsKeyDown(Keys.LeftControl) || keyboard.IsKeyDown(Keys.RightControl))
                && keyboard.IsKeyDown(Keys.R))
            {   // restart
                Start();
            }

            base.Update(gameTime);

            if (_mainBall.CurrentLifeState == Ball.LifeState.Dead)
            {
                Start();
            }
        }

        /// <summary>
        /// This is called when the _game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here
            _spriteBatch.Begin();

            /* Note:                 
             * the pair of _graphics.GraphicsDevice.DisplayMode.Width, _graphics.GraphicsDevice.DisplayMode.Height
             * instead gives the dimensions of the screen the graphic device is currently engaged with
             */
            _spriteBatch.Draw(_backgroundTexture, new Rectangle(0, 0,
                _graphics.PreferredBackBufferWidth, _graphics.PreferredBackBufferHeight),
                Color.LightGray);

            base.Draw(gameTime);

            /*
             * Components might be drawn in base.Draw(...) method, 
             * hence the end drawing method for the batch must be placed after that
             */
            _spriteBatch.End();
        }

        private void Start()
        {
            if (_racket == null)
            {
                _racket = new Racket(this, new Racket.State[] { 
                    new Racket.NormalState(Content.Load<Texture2D>("racket0"), 
                        new Rectangle(0, 0,
                        _graphics.PreferredBackBufferWidth, 
                        _graphics.PreferredBackBufferHeight)),
                    new Racket.FreeState(Content.Load<Texture2D>("racket1"),
                        new Rectangle(0, 0,
                        _graphics.PreferredBackBufferWidth,
                        _graphics.PreferredBackBufferHeight)) 
                    }
                );
                Components.Add(_racket);
            }

            _racket.PutInStartPosition();

            if (_bricks == null)
            {
                _bricks = new Bricks(this,
                    new Rectangle(0, 0, this.Window.ClientBounds.Width, this.Window.ClientBounds.Height));

                Components.Add(_bricks);
            }

            _bricks.LoadBricks();

            if (_mainBall == null)
            {
                _mainBall = new Ball(this, new Ball.State[] {
                    new Ball.NormalState(Content.Load<Texture2D>("ball0"), 
                        new Vector2(10, 10), 
                        new Rectangle(0, 0,
                        _graphics.PreferredBackBufferWidth, 
                        _graphics.PreferredBackBufferHeight), 1.0f) }
                );
                Components.Add(_mainBall);
            }

            _mainBall.PutInStartPosition();

        }
    }
}
